﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using devtm.Aop.Emit;
using devtm.Aop.InternalProcess;
using devtm.Aop.Convert;
using Mono.Cecil;
using System.Reflection;
using devtm.Aop.Linq.Boxs;
using devtm.Aop;
using devtm.Aop.Extensions;


namespace devtm.Aop.Linq
{
    
    public class Proxy
    {


        internal Type Type { get; set; }
        protected IDictionary<string, GroupMethod> _list = new Dictionary<string, GroupMethod>();
        protected IDictionary<Type, InterfaceMapping> _interfaces = new Dictionary<Type, InterfaceMapping>();


        #region Runtime        

        public static ProxyRuntime<T> ForRuntime<T>()
        {

            typeof(T).EnsureIsNotSealed("T");
            typeof(T).EnsureIsNotInterface("T");

            ProxyRuntime<T> p = new ProxyRuntime<T>(typeof(T));

            return p;

        }

        public static Proxy ForRuntime(Type typeProxy)
        {

            typeProxy.EnsureIsNotSealed("type");
            typeProxy.EnsureIsNotInterface("type");

            Type t1 = typeof(ProxyRuntime<>).MakeGenericType(typeProxy);

            Proxy p = Activator.CreateInstance(t1, new object[] { typeProxy }) as Proxy;

            return p;

        }

        #endregion


        #region Build

        public static ProxyBuild<T> ForBuild<T>()
        {

            typeof(T).EnsureIsInterface("T");

            ProxyBuild<T> p = new ProxyBuild<T>(typeof(T));

            return p;

        }

        public static Proxy ForBuild(Type typeProxy)
        {

            typeProxy.EnsureIsInterface("type");

            Type t1 = typeof(ProxyBuild<>).MakeGenericType(typeProxy);

            Proxy p = Activator.CreateInstance(t1, new object[] { typeProxy }) as Proxy;

            return p;

        }

        #endregion

        public GroupMethod GroupMethod()
        {
            return GroupMethod(Guid.NewGuid().ToString());
        }


        public GroupMethod GroupMethod(string label)
        {
            Type t1 = typeof(GroupMethod<>).MakeGenericType(Type);
            GroupMethod g = Activator.CreateInstance(t1, new object[] { t1 }) as GroupMethod;
            _list.Add(label, g);
            return g;
        } 


        #region Implements

        public Proxy Implement(Type implementation, params Type[] interfaces)
        {

            implementation.EnsureImplement(interfaces);

            List<Type> lst = new List<Type>();
            GetAllInterfaces(lst, interfaces);

            foreach (Type t in lst)
                if (!_interfaces.ContainsKey(t))
                {
                    var map = implementation.GetInterfaceMap(t);
                    _interfaces.Add(t, map);
                }
            
            return this;
        }

        private void GetAllInterfaces(List<Type> lst, params Type[] interfaces)
        {

            foreach (Type t in interfaces)            
                if (!lst.Contains(t))
                {
                    lst.Add(t);
                    GetAllInterfaces(lst, t.GetInterfaces());
                }
            
        }


        #endregion
    
    
    }

}
